﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Windows.Forms;
using System.Xml;
using SdmxMl.Common;
using SdmxMl.Helper;
using SdmxMl.Manager;
using SdmxMl.Structure;


namespace SdmxMl.GenericMetadata
{
    /// <summary>
    /// Component values have an object attribute with an object type value as provided
    /// in the metadata structure definition, a component attribute which takes the ID
    /// of the identifier component in the metadata structure definition's full target
    /// identifier, and a value, which must be a valid value for that concept's
    /// representation as described in the metadata structure definition.
    /// </summary>
    public class ComponentValueType : IReportedValue
    {
        #region Properties

        private string _value;
        public  string Value
        {
            get { return _value; }
            set { _value = value; }
        }

        private string _component;
        public virtual string Component
        {
            get { return _component; }
            set { _component = value; }
        }

        private ObjectTypeCodelistType _object;
        public ObjectTypeCodelistType Object
        {
            get { return _object; }
            set { _object = value; }
        }
        #endregion // Properties

        #region Cloning

        public ComponentValueType Clone()
        {
            ComponentValueType clone = new ComponentValueType();
            clone.Component = Component;
            clone.Value = Value;
            clone.Object = Object;

            return clone;
        }

        #endregion


        #region Construction

        public ComponentValueType()
        {
            _object = ObjectTypeCodelistType.Any;
        }

        public ComponentValueType(XmlNode nodeArtefact, XmlNamespaceManager nsmgr)
        {

            _object = ObjectTypeCodelistType.Any;
            string str = Xmlhelper.GetAtt(nodeArtefact, "object").ToLower();
            // Enumeration changed between 2.0 and 2.1, even in casing
            foreach (ObjectTypeCodelistType otc in Enum.GetValues(typeof(ObjectTypeCodelistType)))
                if (otc.ToString().ToLower() == str)
                {
                    _object = otc;
                    break;
                }

            _component = Xmlhelper.GetAtt(nodeArtefact, "component");
            _value = nodeArtefact.InnerText;
        }

        #endregion //Construction

        #region XML serialize

        public void WriteXml(XmlTextWriter xw, string prefix, string tag)
        {
            xw.WriteStartElement(prefix, tag, null);

            // Required
            if (SdmxNamespaceManager.SdmxTarget == SdmxVersion.SDMX_20)
            {
                // as we use a 2.1 enumeration, try to find a match
                string target = "Component"; // choosen as dummy
                string newType = _object.ToString().ToLower();
                // Scan old 2.0 emun
                foreach (ObjectIDType otc in Enum.GetValues(typeof(ObjectIDType)))
                    if (otc.ToString().ToLower() == newType)
                    {
                        target = otc.ToString();
                        break;
                    }

                xw.WriteAttributeString("object", target);
            }



            Xmlhelper.WriteAttributeIfExist(xw, "component", _component);
            // Content value
            xw.WriteString(Value);

            xw.WriteEndElement();
        }

        #endregion //XML serialize

        #region IReportedValue Members

        public MultiLang InternationalizedValue
        {
            get { return null; }
        }

        public string SimpleValue
        {
            get
            {
                return _value;
            }
            set
            {
                _value = value;
            }
        }

        #endregion
    }

    /// <summary> MSD Keys list </summary>
    public class ComponentValueTypeList : List<ComponentValueType>
    {
        #region DataTable representation 

        public static DataTable CreateTable()
        {
            DataTable dataTable = new DataTable();
            dataTable.Columns.Add(new DataColumn("Component", typeof(string)));
            dataTable.Columns.Add(new DataColumn("Object", typeof(string)));
            dataTable.Columns.Add(new DataColumn("Value", typeof(string)));

            return dataTable;
        }

        /// <summary>Presents list as datatable</summary>
        /// <returns>a datatable representation</returns>
        public DataTable AsDataTable()
        {
            DataTable dataTable = CreateTable();

            foreach (ComponentValueType fr in this)
                dataTable.Rows.Add(new object[] { fr.Component, fr.Object.ToString(), fr.Value });

            return dataTable;
        }

        #endregion // DataTable representation

        #region Get/Set component value

        public void SetComponentValue(string id, string val)
        {
            foreach (ComponentValueType cv in this)
            {
                if (cv.Component == id)
                {
                    cv.Value = val;
                    break;
                }
            }
        }
        public string this[string id]
        {
            get
            {
                ComponentValueType cv = GetComponentValue(id);
                return cv == null ? string.Empty : cv.SimpleValue;
            }
        }

        public ComponentValueType GetComponentValue(string id)
        {
            ComponentValueType val = null;
            foreach (ComponentValueType cv in this)
            {
                if (cv.Component == id)
                {
                    val = cv;
                    break;
                }
            }
            return val;
        }
        #endregion
    }
}
